package com.sw.study.monitor;

import com.sw.study.monitor.bean.MethodDataInfo;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Activate(group = CommonConstants.CONSUMER)
public class TpMonitorFilter implements Filter,Runnable {
    private static final ConcurrentMap<String, List<MethodDataInfo>> METHODMAP=new ConcurrentHashMap<>();

    /**
     * 初始化构造函数，启动定时
     * 1.每到5s打印TP99 和TP90
     * 2.每到一分钟删除下数据
     */
    public TpMonitorFilter() {
        /**
         * 此处的this 调用是本类中的run方法
         */
        ScheduledThreadPoolExecutor executorService=new ScheduledThreadPoolExecutor(1);
        executorService.scheduleWithFixedDelay(this,5,5, TimeUnit.SECONDS);

        /**
         * 删除数据
         */
        ScheduledThreadPoolExecutor removeDate=new ScheduledThreadPoolExecutor(1);
        removeDate.scheduleWithFixedDelay(new RemoveData(METHODMAP),5,1, TimeUnit.MINUTES);

    }

    @Override
    public void run() {
        //计算打印
        for(Map.Entry<String,List<MethodDataInfo>> entry:METHODMAP.entrySet()) {
            long tp99 = getTp(entry.getValue(), 0.99);
            long tp90 = getTp(entry.getValue(), 0.90);
            System.out.println("tp99:"+tp99+",tp90:"+tp90);
        }

    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        /**
         * 处理时间
         */
        Long start =System.currentTimeMillis();
        Result result=null;
        Long takeTime=null;
        try {
             result = invoker.invoke(invocation);
        }catch (Exception e){
            throw  new RpcException(e.getMessage());
        }finally {
            insertMethodInfo(invocation.getMethodName(),start);
        }
        return result;
    }

    /**
     * 处理存储
     * @param methodName
     * @param start
     */
    private void insertMethodInfo(String methodName,Long start){
        Long takeTime=System.currentTimeMillis()-start;
        MethodDataInfo methodDataInfo=new MethodDataInfo(methodName,takeTime,System.currentTimeMillis());
        if(METHODMAP.containsKey(methodName)){
            METHODMAP.get(methodName).add(methodDataInfo);
        }else{
            List<MethodDataInfo> methodDataInfos=new ArrayList<>();
            methodDataInfos.add(methodDataInfo);
            METHODMAP.put(methodName,methodDataInfos);
        }
    }

    private long getTp(List<MethodDataInfo> methodDataInfos,double rate){
        Long ennTime=System.currentTimeMillis();
        Long startTime=ennTime-60000;
        int size=methodDataInfos.size();
        MethodDataInfo methodDataInfo=null;
        List<MethodDataInfo> sortList=new ArrayList<>(methodDataInfos.size());
        for(int i=0;i<size;i++){
            methodDataInfo=methodDataInfos.get(i);
            if(methodDataInfo.getEndTimes()>=startTime && methodDataInfo.getEndTimes()<=ennTime){
                sortList.add(methodDataInfo);
            }
        }
        sortList.sort(new Comparator<MethodDataInfo>() {
            @Override
            public int compare(MethodDataInfo o1, MethodDataInfo o2) {
                 if(o1.getTimes()>o2.getTimes()){
                     return 1;
                 }else if(o1.getTimes()<o2.getTimes()){
                     return -1;
                 }else{
                     return 0;
                 }
            }
        });
        int index=(int)(sortList.size()*rate);
        return sortList.get(index).getTimes();
    }
}
